home *** CD-ROM | disk | FTP | other *** search
- unit HVPEUtils;
- { PE-file types missing from the Windows and ImageHlp units.
- These were gleaned from Matt Pietrek's work and WINNT.H
-
- And simple utility routines to access parts of a loaded PE file.
-
- Written by Hallvard Vassbotn, hallvard@balder.no, July 1999
-
- Inspired by Matt Pietrek's article "Peering inside the PE: A Tour of the Win32
- Portable Executable File Format", available at:
- http://msdn.microsoft.com/library/techart/msdn_peeringpe.htm
- }
- interface
-
- uses
- Windows,
- SysUtils;
-
- // ------------------------- START-OF-WINNT.H-STUFF ---------------------------
-
- {$IFDEF VER90}
- // The Delphi 2.0 version of the Windows unit lacks some key definitions:
-
- const
- IMAGE_DOS_SIGNATURE = $5A4D;
- IMAGE_NT_SIGNATURE = $00004550;
- IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
- IMAGE_SIZEOF_SHORT_NAME = 8;
- IMAGE_DIRECTORY_ENTRY_IMPORT = 1;
-
- type
- PImageFileHeader = ^TImageFileHeader;
- TImageFileHeader = packed record
- Machine: Word;
- NumberOfSections: Word;
- TimeDateStamp: DWORD;
- PointerToSymbolTable: DWORD;
- NumberOfSymbols: DWORD;
- SizeOfOptionalHeader: Word;
- Characteristics: Word;
- end;
-
- PImageDataDirectory = ^TImageDataDirectory;
- TImageDataDirectory = record
- VirtualAddress: DWORD;
- Size: DWORD;
- end;
-
- PimageOptionalHeader = ^TImageOptionalHeader;
- TImageOptionalHeader = packed record
- { Standard fields. }
- Magic: Word;
- MajorLinkerVersion: Byte;
- MinorLinkerVersion: Byte;
- SizeOfCode: DWORD;
- SizeOfInitializedData: DWORD;
- SizeOfUninitializedData: DWORD;
- AddressOfEntryPoint: DWORD;
- BaseOfCode: DWORD;
- BaseOfData: DWORD;
- { NT additional fields. }
- ImageBase: DWORD;
- SectionAlignment: DWORD;
- FileAlignment: DWORD;
- MajorOperatingSystemVersion: Word;
- MinorOperatingSystemVersion: Word;
- MajorImageVersion: Word;
- MinorImageVersion: Word;
- MajorSubsystemVersion: Word;
- MinorSubsystemVersion: Word;
- Win32VersionValue: DWORD;
- SizeOfImage: DWORD;
- SizeOfHeaders: DWORD;
- CheckSum: DWORD;
- Subsystem: Word;
- DllCharacteristics: Word;
- SizeOfStackReserve: DWORD;
- SizeOfStackCommit: DWORD;
- SizeOfHeapReserve: DWORD;
- SizeOfHeapCommit: DWORD;
- LoaderFlags: DWORD;
- NumberOfRvaAndSizes: DWORD;
- DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory;
- end;
-
- PImageNtHeaders = ^TImageNtHeaders;
- TImageNtHeaders = packed record
- Signature: DWORD;
- FileHeader: TImageFileHeader;
- OptionalHeader: TImageOptionalHeader;
- end;
-
- TISHMisc = packed record
- case Integer of
- 0: (PhysicalAddress: DWORD);
- 1: (VirtualSize: DWORD);
- end;
-
- PImageSectionHeader = ^TImageSectionHeader;
- TImageSectionHeader = packed record
- Name: packed array[0..IMAGE_SIZEOF_SHORT_NAME-1] of Byte;
- Misc: TISHMisc;
- VirtualAddress: DWORD;
- SizeOfRawData: DWORD;
- PointerToRawData: DWORD;
- PointerToRelocations: DWORD;
- PointerToLinenumbers: DWORD;
- NumberOfRelocations: Word;
- NumberOfLinenumbers: Word;
- Characteristics: DWORD;
- end;
- {$ENDIF}
-
- const
- MaxBlock = MaxInt-$f;
- type
- LONG = DWORD;
- PImageDOSHeader = ^TImageDosHeader;
- TImageDOSHeader = packed record // DOS .EXE header
- e_magic: WORD; // Magic number
- e_cblp: WORD; // Bytes on last page of file
- e_cp: WORD; // Pages in file
- e_crlc: WORD; // Relocations
- e_cparhdr: WORD; // Size of header in paragraphs
- e_minalloc: WORD; // Minimum extra paragraphs needed
- e_maxalloc: WORD; // Maximum extra paragraphs needed
- e_ss: WORD; // Initial (relative) SS value
- e_sp: WORD; // Initial SP value
- e_csum: WORD; // Checksum
- e_ip: WORD; // Initial IP value
- e_cs: WORD; // Initial (relative) CS value
- e_lfarlc: WORD; // File address of relocation table
- e_ovno: WORD; // Overlay number
- e_res: array[0..4-1] of WORD; // Reserved words
- e_oemid: WORD; // OEM identifier (for e_oeminfo)
- e_oeminfo: WORD; // OEM information: e_oemid specific
- e_res2: array[0..10-1] of WORD; // Reserved words
- e_lfanew: LONG; // File address of new exe header
- end;
-
- PImageOS2Header = ^TImageOS2Header;
- TImageOS2Header = packed record // OS/2 .EXE header
- ne_magic: WORD; // Magic number
- ne_ver: CHAR; // Version number
- ne_rev: CHAR; // Revision number
- ne_enttab: WORD; // Offset of Entry Table
- ne_cbenttab: WORD; // Number of bytes in Entry Table
- ne_crc: LONG; // Checksum of whole file
- ne_flags: WORD; // Flag WORD;
- ne_autodata: WORD; // Automatic data segment number
- ne_heap: WORD; // Initial heap allocation
- ne_stack: WORD; // Initial stack allocation
- ne_csip: LONG; // Initial CS:IP setting
- ne_sssp: LONG; // Initial SS:SP setting
- ne_cseg: WORD; // Count of file segments
- ne_cmod: WORD; // Entries in Module Reference Table
- ne_cbnrestab: WORD; // Size of non-resident name table
- ne_segtab: WORD; // Offset of Segment Table
- ne_rsrctab: WORD; // Offset of Resource Table
- ne_restab: WORD; // Offset of resident name table
- ne_modtab: WORD; // Offset of Module Reference Table
- ne_imptab: WORD; // Offset of Imported Names Table
- ne_nrestab: LONG; // Offset of Non-resident Names Table
- ne_cmovent: WORD; // Count of movable entries
- ne_align: WORD; // Segment alignment shift count
- ne_cres: WORD; // Count of resource segments
- ne_exetyp: BYTE; // Target Operating system
- ne_flagsothers: BYTE; // Other .EXE flags
- ne_pretthunks: WORD; // offset to return thunks
- ne_psegrefbytes: WORD; // offset to segment ref. bytes
- ne_swaparea: WORD; // Minimum code swap area size
- ne_expver: WORD; // Expected Windows version number
- end;
-
- PImageVXDHeader = ^TImageVXDHeader;
- TImageVXDHeader = packed record // Windows VXD header
- e32_magic: WORD; // Magic number
- e32_border: BYTE; // The byte ordering for the VXD
- e32_worder: BYTE; // The word ordering for the VXD
- e32_level: DWORD; // The EXE format level for now = 0
- e32_cpu: WORD; // The CPU type
- e32_os: WORD; // The OS type
- e32_ver: DWORD; // Module version
- e32_mflags: DWORD; // Module flags
- e32_mpages: DWORD; // Module # pages
- e32_startobj: DWORD; // Object # for instruction pointer
- e32_eip: DWORD; // Extended instruction pointer
- e32_stackobj: DWORD; // Object # for stack pointer
- e32_esp: DWORD; // Extended stack pointer
- e32_pagesize: DWORD; // VXD page size
- e32_lastpagesize: DWORD; // Last page size in VXD
- e32_fixupsize: DWORD; // Fixup section size
- e32_fixupsum: DWORD; // Fixup section checksum
- e32_ldrsize: DWORD; // Loader section size
- e32_ldrsum: DWORD; // Loader section checksum
- e32_objtab: DWORD; // Object table offset
- e32_objcnt: DWORD; // Number of objects in module
- e32_objmap: DWORD; // Object page map offset
- e32_itermap: DWORD; // Object iterated data map offset
- e32_rsrctab: DWORD; // Offset of Resource Table
- e32_rsrccnt: DWORD; // Number of resource entries
- e32_restab: DWORD; // Offset of resident name table
- e32_enttab: DWORD; // Offset of Entry Table
- e32_dirtab: DWORD; // Offset of Module Directive Table
- e32_dircnt: DWORD; // Number of module directives
- e32_fpagetab: DWORD; // Offset of Fixup Page Table
- e32_frectab: DWORD; // Offset of Fixup Record Table
- e32_impmod: DWORD; // Offset of Import Module Name Table
- e32_impmodcnt: DWORD; // Number of entries in Import Module Name Table
- e32_impproc: DWORD; // Offset of Import Procedure Name Table
- e32_pagesum: DWORD; // Offset of Per-Page Checksum Table
- e32_datapage: DWORD; // Offset of Enumerated Data Pages
- e32_preload: DWORD; // Number of preload pages
- e32_nrestab: DWORD; // Offset of Non-resident Names Table
- e32_cbnrestab: DWORD; // Size of Non-resident Name Table
- e32_nressum: DWORD; // Non-resident Name Table Checksum
- e32_autodata: DWORD; // Object # for automatic data object
- e32_debuginfo: DWORD; // Offset of the debugging information
- e32_debuglen: DWORD; // The length of the debugging info. in bytes
- e32_instpreload: DWORD; // Number of instance pages in preload section of VXD file
- e32_instdemand: DWORD; // Number of instance pages in demand load section of VXD file
- e32_heapsize: DWORD; // Size of heap - for 16-bit apps
- e32_res3: array[0..12-1] of BYTE; // Reserved words
- e32_winresoff: DWORD;
- e32_winreslen: DWORD;
- e32_devid: WORD; // Device ID for VxD
- e32_ddkver: WORD; // DDK version for VxD
- end;
-
- // Convert to function?
- {##define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \
- ((DWORD)ntheader + \
- FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \
- ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader \
- ))}
-
- //
- // Relocation format.
- //
- PImageRelocation = ^TImageRelocation;
- TImageRelocation = packed record
- case integer of
- 0 : (VirtualAddress : DWORD;
- SymbolTableIndex : DWORD;
- RelocType : WORD);
- 1 : (RelocCount : DWORD; // Set to the real count when IMAGE_SCN_LNK_NRELOC_OVFL is set
- SymbolTableIndex_ : DWORD;
- RelocType_ : WORD);
- end;
- const
- IMAGE_SIZEOF_RELOCATION = 10;
-
- const
- //
- // I386 relocation types.
- //
- IMAGE_REL_I386_ABSOLUTE = $0000; // Reference is absolute, no relocation is necessary
- IMAGE_REL_I386_DIR16 = $0001; // Direct 16-bit reference to the symbols virtual address
- IMAGE_REL_I386_REL16 = $0002; // PC-relative 16-bit reference to the symbols virtual address
- IMAGE_REL_I386_DIR32 = $0006; // Direct 32-bit reference to the symbols virtual address
- IMAGE_REL_I386_DIR32NB = $0007; // Direct 32-bit reference to the symbols virtual address, base not included
- IMAGE_REL_I386_SEG12 = $0009; // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address
- IMAGE_REL_I386_SECTION = $000A;
- IMAGE_REL_I386_SECREL = $000B;
- IMAGE_REL_I386_REL32 = $0014; // PC-relative 32-bit reference to the symbols virtual address
-
- //
- // MIPS relocation types.
- //
- IMAGE_REL_MIPS_ABSOLUTE = $0000; // Reference is absolute, no relocation is necessary
- IMAGE_REL_MIPS_REFHALF = $0001;
- IMAGE_REL_MIPS_REFWORD = $0002;
- IMAGE_REL_MIPS_JMPADDR = $0003;
- IMAGE_REL_MIPS_REFHI = $0004;
- IMAGE_REL_MIPS_REFLO = $0005;
- IMAGE_REL_MIPS_GPREL = $0006;
- IMAGE_REL_MIPS_LITERAL = $0007;
- IMAGE_REL_MIPS_SECTION = $000A;
- IMAGE_REL_MIPS_SECREL = $000B;
- IMAGE_REL_MIPS_SECRELLO = $000C; // Low 16-bit section relative referemce (used for >32k TLS)
- IMAGE_REL_MIPS_SECRELHI = $000D; // High 16-bit section relative reference (used for >32k TLS)
- IMAGE_REL_MIPS_REFWORDNB = $0022;
- IMAGE_REL_MIPS_PAIR = $0025;
-
- //
- // Alpha Relocation types.
- //
- IMAGE_REL_ALPHA_ABSOLUTE = $0000;
- IMAGE_REL_ALPHA_REFLONG = $0001;
- IMAGE_REL_ALPHA_REFQUAD = $0002;
- IMAGE_REL_ALPHA_GPREL32 = $0003;
- IMAGE_REL_ALPHA_LITERAL = $0004;
- IMAGE_REL_ALPHA_LITUSE = $0005;
- IMAGE_REL_ALPHA_GPDISP = $0006;
- IMAGE_REL_ALPHA_BRADDR = $0007;
- IMAGE_REL_ALPHA_HINT = $0008;
- IMAGE_REL_ALPHA_INLINE_REFLONG = $0009;
- IMAGE_REL_ALPHA_REFHI = $000A;
- IMAGE_REL_ALPHA_REFLO = $000B;
- IMAGE_REL_ALPHA_PAIR = $000C;
- IMAGE_REL_ALPHA_MATCH = $000D;
- IMAGE_REL_ALPHA_SECTION = $000E;
- IMAGE_REL_ALPHA_SECREL = $000F;
- IMAGE_REL_ALPHA_REFLONGNB = $0010;
- IMAGE_REL_ALPHA_SECRELLO = $0011; // Low 16-bit section relative reference
- IMAGE_REL_ALPHA_SECRELHI = $0012; // High 16-bit section relative reference
-
- //
- // IBM PowerPC relocation types.
- //
- IMAGE_REL_PPC_ABSOLUTE = $0000; // NOP
- IMAGE_REL_PPC_ADDR64 = $0001; // 64-bit address
- IMAGE_REL_PPC_ADDR32 = $0002; // 32-bit address
- IMAGE_REL_PPC_ADDR24 = $0003; // 26-bit address, shifted left 2 (branch absolute)
- IMAGE_REL_PPC_ADDR16 = $0004; // 16-bit address
- IMAGE_REL_PPC_ADDR14 = $0005; // 16-bit address, shifted left 2 (load doubleword)
- IMAGE_REL_PPC_REL24 = $0006; // 26-bit PC-relative offset, shifted left 2 (branch relative)
- IMAGE_REL_PPC_REL14 = $0007; // 16-bit PC-relative offset, shifted left 2 (br cond relative)
- IMAGE_REL_PPC_TOCREL16 = $0008; // 16-bit offset from TOC base
- IMAGE_REL_PPC_TOCREL14 = $0009; // 16-bit offset from TOC base, shifted left 2 (load doubleword)
- IMAGE_REL_PPC_ADDR32NB = $000A; // 32-bit addr w/o image base
- IMAGE_REL_PPC_SECREL = $000B; // va of containing section (as in an image sectionhdr)
- IMAGE_REL_PPC_SECTION = $000C; // sectionheader number
- IMAGE_REL_PPC_IFGLUE = $000D; // substitute TOC restore instruction iff symbol is glue code
- IMAGE_REL_PPC_IMGLUE = $000E; // symbol is glue code; virtual address is TOC restore instruction
- IMAGE_REL_PPC_SECREL16 = $000F; // va of containing section (limited to 16 bits)
- IMAGE_REL_PPC_REFHI = $0010;
- IMAGE_REL_PPC_REFLO = $0011;
- IMAGE_REL_PPC_PAIR = $0012;
-
- IMAGE_REL_PPC_TYPEMASK = $00FF; // mask to isolate above values in IMAGE_RELOCATION.Type
-
- // Flag bits in IMAGE_RELOCATION.TYPE
-
- IMAGE_REL_PPC_NEG = $0100; // subtract reloc value rather than adding it
- IMAGE_REL_PPC_BRTAKEN = $0200; // fix branch prediction bit to predict branch taken
- IMAGE_REL_PPC_BRNTAKEN = $0400; // fix branch prediction bit to predict branch not taken
- IMAGE_REL_PPC_TOCDEFN = $0800; // toc slot defined in file (or, data in toc)
-
- //
- // Based relocation format.
- //
- type
- PImageBaseRelocation = ^TImageBaseRelocation;
- TImageBaseRelocation = packed record
- VirtualAddress: DWORD;
- SizeOfBlock : DWORD;
- TypeOffsets : Array[0..MaxBlock div SizeOf(WORD)] of WORD;
- end;
-
- const
- IMAGE_SIZEOF_BASE_RELOCATION = 8;
-
- //
- // Based relocation types.
- //
-
- IMAGE_REL_BASED_ABSOLUTE = 0;
- IMAGE_REL_BASED_HIGH = 1;
- IMAGE_REL_BASED_LOW = 2;
- IMAGE_REL_BASED_HIGHLOW = 3;
- IMAGE_REL_BASED_HIGHADJ = 4;
- IMAGE_REL_BASED_MIPS_JMPADDR = 5;
-
- //
- // Line number format.
- //
- type
- TImageLineNumber = packed record
- case integer of
- 0 : (SymbolTableIndex: DWORD; // Symbol table index of function name if Linenumber is 0.
- Linenumber : WORD); // Line number.
- 1 : (VirtualAddress : DWORD; // Virtual address of line number.
- Linenumber_ : WORD);
- end;
- const
- IMAGE_SIZEOF_LINENUMBER = 6;
-
- //
- // Archive format.
- //
- IMAGE_ARCHIVE_START_SIZE = 8;
- IMAGE_ARCHIVE_START = '!<arch>'#13#10;
- IMAGE_ARCHIVE_END = '`'#13#10;
- IMAGE_ARCHIVE_PAD = #13#10;
- IMAGE_ARCHIVE_LINKER_MEMBER = '/ ';
- IMAGE_ARCHIVE_LONGNAMES_MEMBER = '// ';
-
- type
- PImageArchiveMemberHeader = ^TImageArchiveMemberHeader;
- TImageArchiveMemberHeader = packed record
- Name : array[0..16-1] of BYTE; // File member name - `/' terminated.
- Date : array[0..12-1] of BYTE; // File member date - decimal.
- UserID : array[0.. 6-1] of BYTE; // File member user id - decimal.
- GroupID : array[0.. 6-1] of BYTE; // File member group id - decimal.
- Mode : array[0.. 8-1] of BYTE; // File member mode - octal.
- Size : array[0..10-1] of BYTE; // File member size - decimal.
- EndHeader: array[0.. 2-1] of BYTE; // String to end header.
- end;
- const
- IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR = 60;
-
- //
- // DLL support.
- //
-
- //
- // Export Format
- //
- type
- PPDWORD = ^PDWORD;
- PPWORD = ^PWORD;
- PImageExportDirectory = ^TImageExportDirectory;
- TImageExportDirectory = packed record
- Characteristics: DWORD;
- TimeDateStamp: DWORD;
- MajorVersion: WORD;
- MinorVersion: WORD;
- Name: DWORD;
- Base: DWORD;
- NumberOfFunctions: DWORD;
- NumberOfNames: DWORD;
- AddressOfFunctions: PPDWORD;
- AddressOfNames: PPDWORD;
- AddressOfNameOrdinals: PPWORD;
- end;
-
- //
- // Import Format
- //
- PImageImportByName = ^TImageImportByName;
- TImageImportByName = packed record
- Hint : WORD;
- Name : array[0..255] of Char;
- end;
-
- PImageThunkData = ^TImageThunkData;
- TImageThunkData = packed record
- case integer of
- 0 : (ForwarderString: PBYTE);
- 1 : (FunctionPtr : PDWORD);
- 2 : (Ordinal : DWORD);
- 3 : (AddressOfData : PImageImportByName);
- end;
-
- const
- IMAGE_ORDINAL_FLAG = DWORD($80000000);
- // Make functions?:
- {## IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG) != 0)
- IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff)}
-
- type
- PImageImportDescriptor = ^TImageImportDescriptor;
- TImageImportDescriptor = packed record
- HintNameTableOffset: DWORD; // RVA to original unbound IAT, aka Characteristics
- // 0 for terminating null import descriptor
- // PImageThunkData
- TimeDateStamp : DWORD; // 0 if not bound,
- // -1 if bound, and real date\time stamp
- // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
- // O.W. date/time stamp of DLL bound to (Old BIND)
- ForwarderChain : DWORD; // -1 if no forwarders
- NameOffset : DWORD; // RVA to name of the module we're importing from
- IATOffset : DWORD; // RVA to IAT (if bound this IAT has actual addresses)
- // PImageThunkData
- end;
-
-
- //
- // New format import descriptors pointed to by DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ]
- //
- type
- PImageBoundImportDescriptor = ^TImageBoundImportDescriptor;
- TImageBoundImportDescriptor = packed record
- TimeDateStamp : DWORD;
- OffsetModuleName : WORD;
- NumberOfModuleForwarderRefs : WORD;
- // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
- end;
-
- TImageBoundForwarderRef = packed record
- TimeDateStamp : DWORD;
- OffsetModuleName : WORD;
- Reserved : WORD;
- end;
- // ------------------------- END-OF-WINNT.H-STUFF -----------------------------
-
- // Utility routines:
-
- function GetImageNtHeader(Base: Pointer): PImageNtHeaders;
- function GetSectionHeader(NtHeader: PImageNtHeaders; SectionName: PChar): PImageSectionHeader;
- function GetFirstSectionHeader(NtHeader: PImageNtHeaders): PImageSectionHeader;
-
- type
- EHookError = class(Exception);
-
- implementation
-
- procedure HookError(const Msg: string);
- begin
- raise EHookError.Create(Msg);
- end;
-
- function GetImageNtHeader(Base: Pointer): PImageNtHeaders;
- var
- DOSHeader: PImageDOSHeader;
- begin
- DOSHeader := PImageDOSHeader(Base);
- if DOSHeader.e_magic <> IMAGE_DOS_SIGNATURE then HookError('Not a valid MZ-file!');
- Result := PImageNtHeaders(DWORD(Base) + DOSHeader.e_lfanew);
- if Result.Signature <> IMAGE_NT_SIGNATURE then HookError('Not a valid PE-file!');
- end;
-
- function GetSectionHeader(NtHeader: PImageNtHeaders; SectionName: PChar): PImageSectionHeader;
- var
- i : integer;
- begin
- Result := PImageSectionHeader(DWORD(NtHeader) + SizeOf(NtHeader^));
- for i := 0 to NtHeader.FileHeader.NumberOfSections-1 do
- begin
- if StrIComp(PChar(@Result.Name), SectionName) = 0 then
- Exit;
- Inc(Result);
- end;
- HookError(Format('Could not find %s section', [SectionName]));
- end;
-
- function GetFirstSectionHeader(NtHeader: PImageNtHeaders): PImageSectionHeader;
- begin
- Result := PImageSectionHeader(DWORD(NtHeader) + SizeOf(NtHeader^));
- end;
-
- end.